#pragma once

#ifndef __MY_HOST__
#define __MY_HOST__

#include "./exchange.hpp"
#include "./msg_queue.hpp"
#include "./binding.hpp"
#include "./message.hpp"

namespace NS_Host
{
    class VirtualHost
    {
    public:
        using Ptr = std::shared_ptr<VirtualHost>;
        VirtualHost(const std::string &host_name, const std::string &basedir, const std::string &dbfilepath)
            : _host_name(host_name), _emp(std::make_shared<NS_Exchange::ExchangeManager>(dbfilepath)), _mqmp(std::make_shared<NS_MsgQueue::MsgQueueManager>(dbfilepath)), _bmp(std::make_shared<NS_Binding::BindingManager>(dbfilepath)), _qmmp(std::make_shared<NS_Message::QueueMessageManager>(basedir))
        {
            // 在四个成员中前三个成员都可以自己将磁盘中的数据恢复到内存中，但是消息的恢复需要得知消息队列的队列名，才能恢复消息到队列中
            const NS_MsgQueue::MsgQueueMap &queues = _mqmp->getMsgQueues();
            for (auto &[qname, ptr] : queues)
            {
                _qmmp->initQueueMessage(qname);
            }
        }

        bool declareExchange(const std::string &name,
                             NS_Message::ExchangeType type,
                             bool durable, bool auto_delete,
                             const google::protobuf::Map<std::string, std::string> &args)
        {
            return _emp->declareExchange(name, type, durable, auto_delete, args);
        }
        void deleteExchange(const std::string &name)
        {
            // 删除交换机时，需要删除交换机相关的一些信息
            // 而与交换机相关的数据有一个那就是，绑定信息
            _bmp->deleteExchangeBindings(name);
            _emp->deleteExchange(name);
        }

        NS_Exchange::Exchange::Ptr selectExchange(const std::string &ename)
        {
            return _emp->selectOne(ename);
        }

        bool declareMsgQueue(const std::string &name,
                             bool exclusive,
                             bool durable, bool auto_delete,
                             const google::protobuf::Map<std::string, std::string> &args)
        {
            // 声明消息队列时，我们需要创建消息的队列单元
            bool ret = true;
            ret = ret && _qmmp->initQueueMessage(name);
            ret = ret && _mqmp->declareMsgQueue(name, exclusive, durable, auto_delete, args);
            return ret;
        }
        void deleteMsgQueue(const std::string &name)
        {
            // 删除消息队列时，需要删除消息队列相关的一些信息
            // 而与交换机相关的数据有两个那就是，绑定信息以及消息队列单元
            _bmp->deleteMsgQueueBindings(name);
            _qmmp->destoryQueueMessage(name);
            _mqmp->deleteMsgQueue(name);
        }
        bool existsMsgQueue(const std::string &qname)
        {
            return _mqmp->exists(qname);
        }

        bool declareBinding(const std::string &ename, const std::string &qname, const std::string &binding_key)
        {
            NS_Exchange::Exchange::Ptr exchange = _emp->selectOne(ename);
            if (exchange == nullptr)
            {
                ELOG("建立绑定关系失败，不存在交换机%s", ename.c_str());
                return false;
            }
            NS_MsgQueue::MsgQueue::Ptr msg_queue = _mqmp->selectOne(qname);
            if (msg_queue == nullptr)
            {
                ELOG("建立绑定关系失败，不存在消息队列%s", qname.c_str());
                return false;
            }
            return _bmp->addBinding(ename, qname, binding_key, (exchange->durable && msg_queue->durable));
        }
        void deleteBinding(const std::string &ename, const std::string &qname)
        {
            _bmp->deleteBinding(ename, qname);
        }
        NS_Binding::MsgQueueBindingMap getExchangeBindings(const std::string &ename)
        {
            return _bmp->getExcahngeBindings(ename);
        }

        bool basicPublish(const std::string &qname, NS_Message::MessageProperties *mp, const std::string &body)
        {
            NS_MsgQueue::MsgQueue::Ptr msg_queue = _mqmp->selectOne(qname);
            if (msg_queue == nullptr)
            {
                ELOG("插入消息失败，不存在消息队列%s", qname.c_str());
                return false;
            }
            NS_Message::DeliveryMode mode = msg_queue->durable ? NS_Message::DeliveryMode::DURABLE : NS_Message::DeliveryMode::UNDURABLE;
            return _qmmp->insert(qname, mp, body, mode);
        }
        
        NS_Message::MessagePtr basicConsume(const std::string &qname)
        {
            return _qmmp->front(qname);
        }
        void basicAck(const std::string &qname, const std::string &msg_id)
        {
            _qmmp->ack(qname, msg_id);
        }

        const NS_MsgQueue::MsgQueueMap& getMsgQueues()
        {
            return _mqmp->getMsgQueues();
        }

        void clear()
        {
            _emp->clear();
            _mqmp->clear();
            _bmp->clear();
            _qmmp->clear();
        }

        size_t exchangeSize()
        {
            return _emp->size();
        }
        size_t msgQueueSize()
        {
            return _mqmp->size();
        }
        size_t bindingSize()
        {
            return _bmp->size();
        }
        size_t queueMsgSize()
        {
            return _qmmp->size();
        }

        ~VirtualHost()
        {

        }

    private:
        std::string _host_name;
        NS_Exchange::ExchangeManager::Ptr _emp;
        NS_MsgQueue::MsgQueueManager::Ptr _mqmp;
        NS_Binding::BindingManager::Ptr _bmp;
        NS_Message::QueueMessageManager::Ptr _qmmp;
    };
}

#endif
